package com.yssw.web.controller.system;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yssw.common.constant.Constants;
import com.yssw.common.core.domain.AjaxResult;
import com.yssw.common.core.domain.entity.SysMenu;
import com.yssw.common.core.domain.entity.SysUser;
import com.yssw.common.core.domain.model.LoginBody;
import com.yssw.common.core.domain.model.LoginUser;
import com.yssw.common.core.domain.model.WxLoginBody;
import com.yssw.common.utils.SecurityUtils;
import com.yssw.common.utils.http.HttpUtils;
import com.yssw.framework.web.service.SysLoginService;
import com.yssw.framework.web.service.SysPermissionService;
import com.yssw.framework.web.service.TokenService;
import com.yssw.system.service.ISysMenuService;
import com.yssw.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.*;

/**
 * 登录验证
 *
 * @author yssw
 */
@Slf4j
@RestController
public class SysLoginController {
    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Value("${wechat-payment.appId}")
    private String appId;

    @Value("${wechat-payment.AppSecret}")
    private String secret;


    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody) {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo() {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        return ajax;
    }

    /**
     * 获取路由信息
     *
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters() {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }

    /**
     * 微信登录
     *
     * @param wxLoginBody 用户相关信息
     * @return Token
     */
    @PostMapping("/wxLogin")
    public AjaxResult wxLogin(@RequestBody WxLoginBody wxLoginBody) {
        if (ObjectUtils.isNotEmpty(wxLoginBody)) {
            //如果解析成功,获取token
            String token = loginService.wxLogin(wxLoginBody);
            AjaxResult ajax = AjaxResult.success();
            ajax.put(Constants.TOKEN, token);
            return ajax;
        } else {
            return AjaxResult.error("微信登录失败！");
        }
    }

    /**
     * 用户授权后获取openId
     *
     * @param code 临时Code
     * @return OpenId
     */
    @PostMapping("/wxCode/{code}")
    public AjaxResult getCode(@PathVariable String code) {
        String res = HttpUtils.sendGet("https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code");
        JSONObject resJSON = JSONObject.parseObject(res);
        AjaxResult ajax = AjaxResult.success();
        ajax.put("openId", resJSON.get("openid"));
        ajax.put("sessionKey", resJSON.get("session_key"));
        return ajax;
    }

    /**
     * 解密微信加密数据
     *
     * @param encryptedData 加密数据
     * @param sessionKey    会话
     * @param iv            偏移量
     * @return 用户数据
     */
    public static String decrypt(String encryptedData, String sessionKey, String iv) {
        try {
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            SecretKeySpec spec = new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(Base64.decodeBase64(iv)));
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
            byte[] resultByte = cipher.doFinal(Base64.decodeBase64(encryptedData));
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, StandardCharsets.UTF_8);
                log.info(">>>>> 微信加密数据解析结果:{}", result);
                return result;
            }
        } catch (Exception e) {
            log.error(">>>>> 微信加密数据解析失败:", e);
        }
        return null;
    }

    /**
     * 根据手机号获取用户信息
     *
     * @param wxLoginBody 手机号
     * @return 用户信息
     */
    @PostMapping("/wxLogin/validate")
    public AjaxResult validateWx(@RequestBody WxLoginBody wxLoginBody) {
        //解密
        String decryptResult = "";
        try {
            //如果没有绑定微信开放平台，解析结果是没有unionid的。
            decryptResult = decrypt(wxLoginBody.getEncryptedData(), wxLoginBody.getSessionKey(), wxLoginBody.getEncryptedIv());
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("微信登录失败！");
        }
        log.info("【根据手机号获取当前登录用户信息】");
        AjaxResult ajax = new AjaxResult();
        try {
            //字符串转json
            JSONObject jsonObject = JSONObject.parseObject(decryptResult);
            //String unionid = jsonObject.getString("unionid");
            String phoneNumber = jsonObject.getString("phoneNumber");
            Map<String, Object> result = new HashMap<>();
            //返回微信登陆者的个人信息
            SysUser sysUser = userService.selectWxUserByPhone(phoneNumber);
            if (sysUser != null) {
                //返回用户信息
                result.put("sysUser", sysUser);
                ajax = AjaxResult.success(result);
            } else {
                result.put("phoneNumber", phoneNumber);
                ajax = new AjaxResult(202,"用户不存在");
            }
        } catch (Exception e) {
            ajax = AjaxResult.error("error");
            log.info("登录验证失败,错误信息:{}", JSONObject.toJSONString(e));
        }
        log.info("【根据手机号获取当前登录用户信息】相应结果：{}", JSON.toJSONString(ajax));
        return ajax;
    }

}
